package cart

import (
	"fmt"
	"strings"

	"mall/common/utils/pointy"
	enum "mall/service/backend/common/enum/promotion"
	"mall/service/forum/api/internal/biz/promotion"
	"mall/service/promotion/rpc/promotionclient"

	"github.com/shopspring/decimal"
	"github.com/sirupsen/logrus"
	// "github.com/zeromicro/go-zero/core/logx"
)

// CouponUseHandler 使用优惠券handler
type CouponUseHandler struct {
	// 合成复用Next
	Next
}

// Do 使用优惠券
func (h *CouponUseHandler) Do(c *Context) (err error) {
	if !c.Resp.StockValid {
		return
	}

	if len(c.Resp.CouponList) == 0 {
		return
	}

	// logx.Infow("使用优惠券...")

	// 优惠券优惠总额
	var couponAmount decimal.Decimal
	for key, coupon := range c.Resp.CouponList {
		// 先假定优惠券不满足条件
		c.Resp.CouponList[key].Status = nil
		// 互斥类型
		if coupon.MutexType != nil && uint8(*coupon.MutexType) == enum.PromotionMutexTypeOrder {
			if _, ok := c.MutexMap[*coupon.MutexType]; ok {
				continue
			}

			c.MutexMap[*coupon.MutexType] = map[uint64]int64{*coupon.Id: -1}
		}

		instance := &promotion.Coupon{}
		var checkScope bool = true

		ctx := &promotion.CouponContext{
			CouponInfo: coupon,
			UserId:     c.UserId,
			UserRank:   strings.ToLower(c.UserRank),
			GemRatio:   c.GemRatio,
			MutexMap:   c.MutexMap,
		}
		var err error
		if err = instance.CheckParams(ctx); err != nil {
			logrus.Info(fmt.Sprintf("CouponUseHandler CheckParams err: %+v", err))
			continue
		}

		// 具体方法：校验优惠券是否在可用时间段内
		if err = instance.CheckTimeRange(ctx); err != nil {
			logrus.Info(fmt.Sprintf("CouponUseHandler CheckTimeRange err: %+v", err))
			continue
		}

		if err = instance.CheckMemberRestriction(ctx); err != nil {
			logrus.Info(fmt.Sprintf("CouponUseHandler CheckMemberRestriction err: %+v", err))
			continue
		}

		var skuIdMap map[uint64]uint64
		if checkScope {
			// 适用范围
			skuIdMap, err = h.checkScope(c, *ctx.CouponInfo.Id, c.SkuScopeInfos)
			if err != nil {
				logrus.Info(fmt.Sprintf("CouponUseHandler checkScope err: %+v", err))
				continue
			}
		}

		pricingInfos, orderPricingInfos := h.initPricingInfos(c, skuIdMap)
		ctx.PricingInfos = pricingInfos
		ctx.OrderPricingInfos = orderPricingInfos

		// 获取SKU定价信息
		if err = instance.GetPricingInfo(ctx); err != nil { // 可能根据 PricingInfos 应用的优惠，修正 OrderPricingInfos
			logrus.Info(fmt.Sprintf("CouponUseHandler GetPricingInfo err: %+v", err))
			continue
		}

		// 获取订单定价信息
		if err = instance.GetOrderPricingInfo(ctx); err != nil { // 可能根据 OrderPricingInfos 应用的优惠，修正 PricingInfos
			logrus.Info(fmt.Sprintf("CouponUseHandler GetOrderPricingInfo err: %+v", err))
			continue
		}

		var related int
		for k, info := range ctx.OrderPricingInfos {
			// logrus.Info(fmt.Sprintf("CouponUseHandler GetOrderPricingInfo: %+v", info))

			if k == 0 {
				continue
			}

			if info.CouponTemplateId == int64(*coupon.TemplateId) {
				if related == 0 && info.Status > 0 {
					related = 1
				}
				if related >= 0 && info.Status < 0 {
					related = -1
				}
			}

			// 未满足条件的
			if info.Status < 0 {
				c.Resp.CouponList[key].Threshold = pointy.GetPointer(info.Threshold)
				c.Resp.CouponList[key].Margin = info.Margin
				if c.Resp.CouponList[key].CouponTemplateInfo.ModeText != nil {
					if tips := strings.Split(*c.Resp.CouponList[key].CouponTemplateInfo.ModeText, ","); len(tips) == 2 {
						tips[0] = strings.Replace(tips[0], "N", info.Threshold, 1)
						tips[1] = strings.Replace(tips[1], "M", info.Margin, 1)
						c.Resp.CouponList[key].Tips = strings.Join(tips, " ")
					}
				}
			}

			// 已满足条件的
			if info.Status > 0 {
				c.Resp.CouponList[key].Threshold = pointy.GetPointer(info.Threshold)
				if c.Resp.CouponList[key].CouponTemplateInfo.ModeText != nil {
					if tips := strings.Split(*c.Resp.CouponList[key].CouponTemplateInfo.ModeText, ","); len(tips) == 2 {
						c.Resp.CouponList[key].Tips = strings.Replace(tips[0], "N", info.Threshold, 1)
					}
				}

				c.Modifiers = append(c.Modifiers, &Modifier{
					CouponId:         info.CouponId,
					CouponTemplateId: info.CouponTemplateId,
					CouponAmount:     info.CouponAmount,
					Status:           info.Status,
					Effect:           info.Effect,
					EffectType:       info.EffectType,
					EffectValue:      info.EffectValue,
				})
				couponAmount = couponAmount.Add(info.CouponAmount)
				c.FinalAmount = c.FinalAmount.Sub(info.CouponAmount)
			}
		}

		if related == 1 {
			c.Resp.CouponList[key].Status = pointy.GetPointer(uint32(1))
		} else if related == -1 {
			c.Resp.CouponList[key].Status = pointy.GetPointer(uint32(0))
		}

		// logrus.Info(fmt.Sprintf("============================================================\n"))
	}

	c.CouponAmount = couponAmount

	return
}

func (h *CouponUseHandler) checkScope(
	c *Context,
	couponId uint64,
	skuScopeInfos []*promotionclient.SkuScopeInfo,
) (skuIdMap map[uint64]uint64, err error) {
	res, err := c.SvcCtx.PromotionRpc.CheckCouponScope(c.Ctx, &promotionclient.CheckCouponScopeReq{
		CouponId: couponId,
		Skus:     skuScopeInfos,
	})
	if err != nil {
		return nil, err
	}

	// logrus.Info(fmt.Sprintf("CouponUseHandler CheckCouponScope res: %+v", res))

	if res.TemplateId == uint64(0) { // 全部商品
		return nil, nil
	}

	skuIdMap = make(map[uint64]uint64)
	if len(res.SkuIds) == 0 { // 没有商品
		return skuIdMap, nil
	}

	for _, skuId := range res.SkuIds {
		skuIdMap[skuId] = couponId
	}

	return skuIdMap, nil
}

func (h *CouponUseHandler) initPricingInfos(
	c *Context,
	skuIdMap map[uint64]uint64,
) (pricingInfos []*promotion.PricingInfo, orderPricingInfos []*promotion.OrderPricingInfo) {
	var skusNumber int64
	var skusAmount decimal.Decimal
	for _, info := range c.PricingInfos {
		if skuIdMap != nil {
			if _, ok := skuIdMap[info.SkuId]; !ok {
				continue
			}
		}

		skusNumber += info.SkuNumber
		skusAmount = skusAmount.Add(info.SkuAmount)
		pricingInfos = append(pricingInfos, info)
	}

	orderPricingInfos = append(orderPricingInfos, &promotion.OrderPricingInfo{
		SkusNumber:  skusNumber,
		SkusAmount:  skusAmount,
		FinalAmount: c.FinalAmount,
	})

	return
}
